package com.example.infrastructure.parser;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * @Author moyin
 * @Description TODO
 * @Date 2025/3/11 02:33
 * @Email 82400672@qq.com
 **/
@Slf4j
public class PluginConfigExtract {

    @SneakyThrows
    public static List<PluginConfigModel> extract(MultipartFile file){
        List<File> jars = extractInstrumentedJars(file);

        List<PluginConfigModel> pluginConfigs =  jars.stream()
                .map(PluginConfigExtract::parsePluginXml)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        return pluginConfigs;
    }


    private static List<File> extractInstrumentedJars(MultipartFile zipFile) throws IOException {
        List<File> result = new ArrayList<>();
        try (ZipArchiveInputStream zis = new ZipArchiveInputStream(
                zipFile.getInputStream(), "GBK", true)) {

            ZipArchiveEntry entry;
            while ((entry = zis.getNextZipEntry()) != null) {
                if (isTargetJar(entry, zipFile.getOriginalFilename())) {
                    File tempJar = extractJarToTemp(zis, entry.getName());
                    result.add(tempJar);
                }
            }
        }
        return result;
    }

    private static File extractJarToTemp(ZipArchiveInputStream zis, String entryName)
            throws IOException {
        // 创建带前缀的临时文件（自动删除）
        File tempFile = File.createTempFile("instrumented-", ".jar");
        tempFile.deleteOnExit();

        try (FileOutputStream fos = new FileOutputStream(tempFile)) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = zis.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
        }
        return tempFile;
    }

    private static PluginConfigModel parsePluginXml(File jarFile) {
        try (ZipFile zip = new ZipFile(jarFile)) {
            ZipEntry xmlEntry = zip.getEntry("META-INF/plugin.xml");
            if (xmlEntry == null) return null;

            try (InputStream xmlStream = zip.getInputStream(xmlEntry)) {
                return PluginConfigDomParser.parse(xmlStream);
            }
        } catch (Exception e) {
            log.error("解析失败: {}", jarFile.getName(), e);
            return null;
        }
    }

    private static boolean isTargetJar(ZipArchiveEntry entry, String fileName) {
        String name = fileName.substring(0, fileName.lastIndexOf(".")) + ".jar";
        String path = entry.getName().replace("\\", "/");
        return (path.contains("/lib/instrumented") || path.endsWith(name))
                && path.endsWith(".jar")
                && !entry.isDirectory();
    }
}
